using Crawler.DataServices.Persistence.nHibernate.Conventions;
using Crawler.Domain.DataEntities;
using Crawler.Domain.DataEntities.Crawling;
using Crawler.Domain.DataEntities.Extracted;
using Crawler.DomainServices.DataServices;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;

namespace Crawler.DataServices.Persistence.nHibernate
{
	internal abstract class SessionFactoryProvider : ISessionFactoryProvider
	{
		private static ISessionFactory _moviesSessionFactory;
		private static ISessionFactory _crawlingSessionFactory;
		private static readonly object SyncLock = new object();
		protected IDataServicesConfiguration Configuration { get; private set; }

		protected SessionFactoryProvider(IDataServicesConfiguration configuration)
		{
			Configuration = configuration;
		}

		public ISessionFactory MoviesSessionFactory
		{
			get
			{
				if (_moviesSessionFactory == null)
					lock (SyncLock)
						if (_moviesSessionFactory == null)
						{
							IPersistenceConfigurer connStr = GetMoviesDbConnectionString();


							_moviesSessionFactory = BuildSessionFactory(connStr, typeof (Movie).Namespace);
						}
				return _moviesSessionFactory;
			}
		}

		public ISessionFactory CrawlingSessionFactory
		{
			get
			{
				if (_crawlingSessionFactory == null)
					lock (SyncLock)
						if (_crawlingSessionFactory == null)
						{
							IPersistenceConfigurer connStr = GetCrawlDbConnectionString();
							_crawlingSessionFactory = BuildSessionFactory(connStr, typeof (RawPageCrawlInfo).Namespace);
						}
				return _crawlingSessionFactory;
			}
		}


		private ISessionFactory BuildSessionFactory(IPersistenceConfigurer connStr,
			string nsEntities)
		{
			FluentConfiguration fluentConfiguration = Fluently.Configure()
				.Database(connStr)
				.Mappings(m =>
					m.AutoMappings.Add(AutoMap.AssemblyOf<Movie>().Where(
						t => t.Namespace.StartsWith(nsEntities) || t == typeof (CrawlingSession))
						.Conventions.AddFromAssemblyOf<CascadeConvention>()
						//.Where(c => c.Namespace.StartsWith(typeof(CascadeConvention).Namespace))
						));
			if (Configuration.CreateDb)
				fluentConfiguration = fluentConfiguration
					.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true));

			return fluentConfiguration
				.BuildSessionFactory();
		}

		protected abstract IPersistenceConfigurer GetMoviesDbConnectionString();
		protected abstract IPersistenceConfigurer GetCrawlDbConnectionString();
	}
}